﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;
using System.Windows.Media.Imaging;
using System.IO;
using System.Windows.Resources;

namespace SilverlightGame
{
    public class ApplicationManager
    {
        public const double TIME_BETWEEN_POWERUPS = 5;
        public const double TIME_BETWEEN_BACKGROUNDS = 3;
        public double timeBetweenEnemies = 2;
        public const string SCORE_ISOSTORE_NAME = "score";
        public const string LIVES_ISOSTORE_NAME = "lives";
        public const string LEVEL_ISOSTORE_NAME = "level";
        public static string START_STATE = "start";
        public const string ENEMYWEAPON = "enemyweapon";
        public const string PLAYERWEAPON = "playerweapon";
        public const string POWERUP = "powerup";
        public const string ENEMY = "enemy";
        public const string PLAYER = "player";
        public const int POWERUP_Z = 10;
        public const int BACKGROUND_Z = 5;
        public const int PLAYER_Z = 10;
        protected static ApplicationManager instance = null;
        protected Player plane = null;    
        protected Random rand = new Random((int)DateTime.Now.Ticks);
        protected double timeSinceLastEnemy = 0;
        protected double timeSinceLastBackground = 0;
        protected double timeSinceLastPowerup = 0;
        protected int score = 0;
        protected TextBlock txtbScore = null;
        protected int lives = 0;
        protected TextBlock txtbLives = null;
        protected int enemySpeedMod = 0;
        protected bool diffJustChanged = false;
        protected TextBlock txtbHelp = null;
        protected int level = 0;
        protected TextBlock txtbLevel = null;

        public static ApplicationManager Instance
        {
            get
            {
                if (instance == null)
                    instance = new ApplicationManager();
                return instance;
            }
        }

        public int SavedScore
        {
            get
            {
                if (IsolatedStorageSettings.ApplicationSettings.Contains(SCORE_ISOSTORE_NAME))
                {
                    int? value = IsolatedStorageSettings.ApplicationSettings[SCORE_ISOSTORE_NAME] as int?;
                    if (value != null) return value.Value;
                }

                return 0;
            }
            set
            {
                IsolatedStorageSettings.ApplicationSettings[SCORE_ISOSTORE_NAME] = value;
            }
        }

        public int Score
        {
            get
            {
                return score;
            }

            set
            {
                score = value;
                if (txtbScore != null) txtbScore.Text = "Score: " + score.ToString();

                // update level
                Level = Score / 100;
            }
        }
        public int SavedLives
        {
            get
            {
                if (IsolatedStorageSettings.ApplicationSettings.Contains(LIVES_ISOSTORE_NAME))
                {
                    int? value = IsolatedStorageSettings.ApplicationSettings[LIVES_ISOSTORE_NAME] as int?;
                    if (value != null) return value.Value;
                }

                return 0;
            }
            set
            {
                IsolatedStorageSettings.ApplicationSettings[LIVES_ISOSTORE_NAME] = value;
            }
        }

        public int Lives
        {
            get
            {
                return lives;
            }

            set
            {
                lives = value;
                if (txtbLives != null) txtbLives.Text = "Lives: " + lives.ToString();
            }
        }
        public int SavedLevel
        {
            get
            {
                if (IsolatedStorageSettings.ApplicationSettings.Contains(LEVEL_ISOSTORE_NAME))
                {
                    int? value = IsolatedStorageSettings.ApplicationSettings[LEVEL_ISOSTORE_NAME] as int?;
                    if (value != null) return value.Value;
                }

                return 0;
            }
            set
            {
                IsolatedStorageSettings.ApplicationSettings[LEVEL_ISOSTORE_NAME] = value;
            }
        }

        public int Level
        {
            get
            {
                return level;
            }

            set
            {
                level = value;
                if (txtbLevel != null) txtbLevel.Text = "Level: " + level.ToString();
            }
        }
        protected ApplicationManager()
        {

        }

        protected void removeAllCanvasChildren()
        {
            UIElementCollection children = (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children;
            while (children.Count != 0)
                children.RemoveAt(0);
        }

        public void startupApplicationManager()
        {
            StateManager.Instance.registerStateChange(
                START_STATE,
                new StateChangeInfo.StateFunction(startMainMenu),
                new StateChangeInfo.StateFunction(endMainMenu));

            StateManager.Instance.registerStateChange(
                "game",
                new StateChangeInfo.StateFunction(startGame),
                new StateChangeInfo.StateFunction(exitGame));

            Score = SavedScore;
            Lives = SavedLives;
            Level = SavedLevel;
        }

        public void startMainMenu()
        {

            Button btnStart = new Button();
            btnStart.Content = "Start Game";
            btnStart.Width = 100;
            btnStart.Height = 35;
            btnStart.SetValue(Canvas.LeftProperty, 490.0);
            btnStart.SetValue(Canvas.TopProperty, 355.0);
            btnStart.Click += delegate(object sender, RoutedEventArgs e) { StateManager.Instance.setState("game"); };         
            (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Add(btnStart);

            txtbHelp = new TextBlock();
            txtbHelp.Text = " Start Game: Click Button \n End Game: Esc \n Move: WSAD Keys \n Fire: Space";
            txtbHelp.Width = 100;
            txtbHelp.Height = 35;
            txtbHelp.FontSize = 20;
            txtbHelp.Foreground = new SolidColorBrush(Colors.White);
            txtbHelp.SetValue(Canvas.LeftProperty, 10.0);
            txtbHelp.SetValue(Canvas.TopProperty, 10.0);
            // we have to insert any non GameObjects at the end of the children collection
            (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Insert(
                (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Count, txtbHelp);
        }

        public void endMainMenu()
        {
            removeAllCanvasChildren();
        }

        public void startGame()
        {
            // initialise collisions
            CollisionManager.Instance.addCollisionMapping(PLAYER, ENEMY);
            CollisionManager.Instance.addCollisionMapping(PLAYER, ENEMYWEAPON);
            CollisionManager.Instance.addCollisionMapping(PLAYERWEAPON, ENEMY);
            CollisionManager.Instance.addCollisionMapping(PLAYER, POWERUP);

            plane = new Player();
            plane.startupPlayer(
                new Point(59, 43),
                new AnimationData(
                    new string[] { "Media/brownplane1.png", "Media/brownplane2.png", "Media/brownplane3.png" },
                    10),
                PLAYER_Z);
            plane.Position = new Point(150, 75);

            Score = 0;
            Level = 0;
            timeBetweenEnemies = 2;
            diffJustChanged = false;
            enemySpeedMod = 0;

            txtbScore = new TextBlock();
            txtbScore.Text = "Score: " + ApplicationManager.Instance.Score.ToString();
            txtbScore.Width = 100;
            txtbScore.Height = 35;
            txtbScore.FontSize = 20;
            txtbScore.Foreground = new SolidColorBrush(Colors.White);
            txtbScore.SetValue(Canvas.LeftProperty, 10.0);
            txtbScore.SetValue(Canvas.TopProperty, 10.0);
            // we have to insert any non GameObjects at the end of the children collection
            (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Insert(
                (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Count, txtbScore);

            txtbLives = new TextBlock();
            txtbLives.Text = "Lives: " + ApplicationManager.Instance.Lives.ToString();
            txtbLives.Width = 100;
            txtbLives.Height = 35;
            txtbLives.FontSize = 20;
            txtbLives.Foreground = new SolidColorBrush(Colors.White);
            txtbLives.SetValue(Canvas.LeftProperty, 300.0);
            txtbLives.SetValue(Canvas.TopProperty, 10.0);
            // we have to insert any non GameObjects at the end of the children collection
            (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Insert(
                (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Count, txtbLives);

            txtbLevel = new TextBlock();
            txtbLevel.Text = "Level: " + ApplicationManager.Instance.Level.ToString();
            txtbLevel.Width = 100;
            txtbLevel.Height = 35;
            txtbLevel.FontSize = 20;
            txtbLevel.Foreground = new SolidColorBrush(Colors.White);
            txtbLevel.SetValue(Canvas.LeftProperty, 510.0);
            txtbLevel.SetValue(Canvas.TopProperty, 10.0);
            // we have to insert any non GameObjects at the end of the children collection
            (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Insert(
                (SilverlightGame.App.Current.RootVisual as Page).LayoutRoot.Children.Count, txtbLevel);
        }

        public void resetGame()
        {
            ApplicationManager.Instance.exitGame();
            StateManager.Instance.endCurrentState();
            StateManager.Instance.setState(StateManager.START_STATE);
        }

        public void exitGame()
        {
            while (GameObject.gameObjects.Count != 0)
                GameObject.gameObjects[0].shutdown();            

            removeAllCanvasChildren();
            txtbScore = null;
            txtbLives = null;
            txtbLevel = null;
        }

        public void enterFrame(double dt)
        {
            if (KeyHandler.Instance.isKeyPressed(Key.Escape) && StateManager.Instance.CurrentState.Equals("game"))
            {
                ApplicationManager.Instance.resetGame();
            }

            timeSinceLastEnemy -= dt;
            timeSinceLastBackground -= dt;
            timeSinceLastPowerup -= dt;

            if (timeSinceLastEnemy <= 0)
            {
                if (Score % 100 == 0 && !diffJustChanged)
                {
                    enemySpeedMod += 25;
                    if(timeBetweenEnemies > .25)
                    {
                        timeBetweenEnemies = timeBetweenEnemies - .25;
                    }
                }
                timeSinceLastEnemy = timeBetweenEnemies;
                Enemy.UnusedEnemy.startupBasicEnemy(
                    new Point(32, 32),
                    new AnimationData(
                        new string[] { "Media/blueplane1.png", "Media/blueplane2.png", "Media/blueplane3.png" },
                        10),
                    10,
                    PLAYER_Z, enemySpeedMod)
                    .Position =
                        new Point(rand.Next(0, (int)(SilverlightGame.App.Current.RootVisual as Page).Width), -32);
            }

            if (timeSinceLastBackground <= 0)
            {
                timeSinceLastBackground = TIME_BETWEEN_BACKGROUNDS;
                BackgroundGameObject.UnusedBackgroundGameObject.startupBackgroundGameObject(
                    new Point(65, 65),
                    "Media/bigisland.png",
                    BACKGROUND_Z)
                    .Position =
                        new Point(rand.Next(0, (int)(SilverlightGame.App.Current.RootVisual as Page).Width), -65);
            }

            if (timeSinceLastPowerup <= 0)
            {
                timeSinceLastPowerup = TIME_BETWEEN_POWERUPS;
                Powerup.UnusedPowerup.startupBasicPowerup(
                    new Point(32, 32),
                    new AnimationData(
                        new string[] { "Media/powerup1.png", "Media/powerup2.png", "Media/powerup3.png" },
                        10),
                    10,
                    POWERUP_Z)
                    .Position =
                        new Point(rand.Next(0, (int)(SilverlightGame.App.Current.RootVisual as Page).Width), -32);
            }
        }

        public void shutdown()
        {
            SavedScore = Score;
            SavedLevel = Level;
            SavedLives = Lives;
        }

        public static string ExecutingAssemblyName
        {
            get
            {
                string name = System.Reflection.Assembly.GetExecutingAssembly().FullName;
                return name.Substring(0, name.IndexOf(','));
            }
        }

        public static Stream GetStream(string relativeUri, string assemblyName)
        {
            StreamResourceInfo res = Application.GetResourceStream(new Uri(assemblyName + ";component/" + relativeUri, UriKind.Relative));
            if (res == null)
            {
                res = Application.GetResourceStream(new Uri(relativeUri, UriKind.Relative));
            }
            if (res != null)
            {
                return res.Stream;
            }
            else
            {
                return null;
            }
        }

        public static Stream GetStream(string relativeUri)
        {
            return GetStream(relativeUri, ExecutingAssemblyName);
        }

        public static BitmapImage GetBitmap(string relativeUri, string assemblyName)
        {
            Stream s = GetStream(relativeUri, assemblyName);
            if (s == null) return null;
            using (s)
            {
                BitmapImage bmp = new BitmapImage();
                bmp.SetSource(s);
                return bmp;
            }
        }

        public static BitmapImage GetBitmap(string relativeUri)
        {
            return GetBitmap(relativeUri, ExecutingAssemblyName);
        }

        public static string GetString(string relativeUri, string assemblyName)
        {
            Stream s = GetStream(relativeUri, assemblyName);
            if (s == null) return null;
            using (StreamReader reader = new StreamReader(s))
            {
                return reader.ReadToEnd();
            }
        }

        public static string GetString(string relativeUri)
        {
            return GetString(relativeUri, ExecutingAssemblyName);
        }

        public static FontSource GetFontSource(string relativeUri, string assemblyName)
        {
            Stream s = GetStream(relativeUri, assemblyName);
            if (s == null) return null;
            using (s)
            {
                return new FontSource(s);
            }
        }

        public static FontSource GetFontSource(string relativeUri)
        {
            return GetFontSource(relativeUri, ExecutingAssemblyName);
        }

        public static object GetXamlObject(string relativeUri, string assemblyName)
        {
            string str = GetString(relativeUri, assemblyName);
            if (str == null) return null;
            object obj = System.Windows.Markup.XamlReader.Load(str);
            return obj;
        }

        public static object GetXamlObject(string relativeUri)
        {
            return GetXamlObject(relativeUri, ExecutingAssemblyName);
        }

    }
}
